﻿/**
 * Vector2
 * 
 * @author		Allen Chou
 * @version		1.0.3 (last update: Jun 29 2008)
 * @link        http://cjcat.blogspot.com
 * @link		http://cjcat2266.deviantart.com
 */

/*
 * Copyright 2008 (C) Allen Chou (cjcat2266@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package idv.cjcat.geom {
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	
	import idv.cjcat.*;
	
	public class Vector2 {
		
		public var info:EventDispatcher = new EventDispatcher();
		
		protected var _x:Number;
		protected var _y:Number;
		
		public static function posVec(object:DisplayObject):Vector2 {
			return new Vector2(object.x, object.y);
		}
		
		public static function setPos(object:DisplayObject, vector:Vector2, offsetX:Number = 0, offsetY:Number = 0):void {
			object.x = vector.x + offsetX;
			object.y = vector.y + offsetY;
		}
		
		public static function stepPos(object:DisplayObject, vector:Vector2, offsetX:Number = 0, offsetY:Number = 0):void {
			object.x += vector.x + offsetX;
			object.y += vector.y + offsetY;
		}
		
		public static function sum(...vectors):Vector2 {
			var tempX:Number = 0;
			var tempY:Number = 0;
			
			for (var i:int = 0; i < vectors.length; i++) {
				tempX += Vector2(vectors[i]).x;
				tempY += Vector2(vectors[i]).y;
			}
			
			return new Vector2(tempX, tempY);
		}
		
		public static function relative(from:Vector2, to:Vector2):Vector2 {
			return new Vector2(to.x - from.x, to.y - from.y);
		}
		
		public function Vector2(x:Number = 0, y:Number = 0) {
			_x = x;
			_y = y;
		}
		
		public function clone():Vector2 {
			return new Vector2(x, y);
		}
		
		public function add(vector:Vector2):Vector2 {
			return new Vector2(x + vector.x, y + vector.y);
		}
		
		public function dot(vector:Vector2):Number {
			return (x * vector.x) + (y * vector.y);
		}
		
		public function project(target:Vector2):Vector2 {
			target = target.unitVec();
			target.length = this.dot(target);
			return target;
		}
		
		public function rotate(angle:Number, radian:Boolean = true, clockwise:Boolean = false):Vector2 {
			var factor:Number = (clockwise)?(-1):(1);
			if (!radian) angle = angle * Math.PI / 180;
			
			var temp:Vector2 = new Vector2(x * Math.cos(angle) + y * factor * Math.sin(angle), -x * factor * Math.sin(angle) + y * Math.cos(angle));
			temp.length = CJMath.setPrecision(temp.length, 10);
			
			return temp;
		}
		
		public function unitVec():Vector2 {
			if (length == 0) return new Vector2();
			return new Vector2(CJMath.setPrecision(x / length, 10), CJMath.setPrecision(y / length, 10));
		}
		
		public function get length():Number {
			return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
		}
		
		public function set length(value:Number):void {
			var leng:Number = length;
			_x = _x * value / leng;
			_y = _y * value / leng;
			info.dispatchEvent(new Event(Event.CHANGE));
		}
		
		public function get x():Number {
			return _x;
		}
		
		public function set x(value:Number):void {
			_x = value;
			info.dispatchEvent(new Event(Event.CHANGE));
		}
		
		public function get y():Number {
			return _y;
		}
		
		public function set y(value:Number):void {
			_y = value;
			info.dispatchEvent(new Event(Event.CHANGE));
		}
		
		public function toVector2P():Vector2P {
			
			return new Vector2P(length, Math.atan2(y, x));
		}
		
		public function toPoint():Point {
			return new Point(x, y);
		}
		
		public function toString():String {
			return "(x = " + x + ", y = " + y + ")";
		}
		
	}
	
}